package com.example.glgk.service.IndicatorAnalysisService;

import com.example.glgk.VO.CurrentPeriodIndicatorValueVO;
import com.example.glgk.VO.DepartmentVO;
import com.example.glgk.VO.IndicatorDataEntityVO;
import com.example.glgk.VO.PieChartDataVO;
import com.example.glgk.dto.QueryEscalation;
import com.example.glgk.dto.indicatorAnalysisDto.DepartmentDto;
import com.example.glgk.dto.indicatorAnalysisDto.IndicatorDataEntityDto;
import com.example.glgk.dto.indicatorAnalysisDto.MulIndicatorDataDto;
import com.example.glgk.entity.DepartmentIndicatorEntity;
import com.example.glgk.entity.ElementDataEntity;
import com.example.glgk.entity.IndicatorDataEntity;
import com.example.glgk.mapper.ElementDataDayMapper;
import com.example.glgk.mapper.ElementDataMapper;
import com.example.glgk.mapper.indicatorAnalysis.IndicatorAnalysisMapper;
import com.example.glgk.utils.Calculator;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.stream.Collectors;

/**
 *
 */
@Service
@Slf4j
public class IndicatorAnalysisService {

    @Autowired
    IndicatorAnalysisMapper indicatorAnalysisMapper;

    @Autowired
    ElementDataMapper elementDataMapper;


    public List<IndicatorDataEntityVO> queryIndicatorList() {
        List<IndicatorDataEntityVO> list = indicatorAnalysisMapper.queryIndicatorList();
        return list;
    }


    public IndicatorDataEntityVO queryIndicatorDataInfo(IndicatorDataEntityDto indicatorDataEntityDto) {
        String id = indicatorDataEntityDto.getId();
        MulIndicatorDataDto mulIndicatorDataDto = indicatorAnalysisMapper.selectById(id);

        IndicatorDataEntityVO indicatorDataEntityVO = new IndicatorDataEntityVO();
        indicatorDataEntityVO.setId(id);
        indicatorDataEntityVO.setIndexName(mulIndicatorDataDto.getIndexName());

        //计算本期指标情况
        currentPeriodIndicatorData(indicatorDataEntityDto, mulIndicatorDataDto, indicatorDataEntityVO);

        // 计算本期科室情况
        /**
         * 1.查出47个科室
         * 2.计算出每个科室的本期指标值及同比指标值  当每个指标项的子指标都来自于系统表才计算  计算只取系统表
         */
        if (indicatorDataEntityDto.getDepartmentLink().equals("1")) {
            List<DepartmentDto> departmentDtoList = indicatorAnalysisMapper.getDepartments();
            indicatorDataEntityDto.setDepartmentDtoList(departmentDtoList);
            currentPeriodDepartmentData(indicatorDataEntityDto, mulIndicatorDataDto, indicatorDataEntityVO);
        }


        // 计算科室趋势占比图例  创建一个饼图占比vo
        departmentTendencyChart(indicatorDataEntityDto, mulIndicatorDataDto, indicatorDataEntityVO);


        return indicatorDataEntityVO;

    }

    /**
     * 计算科室趋势占比图例
     *
     * @param indicatorDataEntityDto
     * @param mulIndicatorDataDto
     * @param indicatorDataEntityVO
     */
    private void departmentTendencyChart(IndicatorDataEntityDto indicatorDataEntityDto, MulIndicatorDataDto mulIndicatorDataDto, IndicatorDataEntityVO indicatorDataEntityVO) {
        //科室数量
        BigDecimal departmentCount = BigDecimal.valueOf(indicatorDataEntityDto.getDepartmentDtoList().size());
        //持平科室数量
        BigDecimal banlanceCount = BigDecimal.valueOf(indicatorDataEntityVO.getBanlanceList() == null ? 0 : indicatorDataEntityVO.getBanlanceList().size());
        //持续持平科室数量
        BigDecimal keepBanlanceCount = BigDecimal.valueOf(indicatorDataEntityVO.getKeepBanlanceList() == null ? 0 : indicatorDataEntityVO.getKeepBanlanceList().size());
        //进步科室数量
        BigDecimal advanceCount=BigDecimal.valueOf(indicatorDataEntityVO.getAdvanceList()==null?0:indicatorDataEntityVO.getAdvanceList().size());
        //持续进步科室数量
        BigDecimal keepAdvancesCount=BigDecimal.valueOf(indicatorDataEntityVO.getKeepAdvanceList()==null?0:indicatorDataEntityVO.getKeepAdvanceList().size());
        //退步科室
        BigDecimal behindCount=BigDecimal.valueOf(indicatorDataEntityVO.getBehindList()==null?0:indicatorDataEntityVO.getBehindList().size());
        //持续退步科室
        BigDecimal keepBehindCount=BigDecimal.valueOf(indicatorDataEntityVO.getKeepBehindList()==null?0:indicatorDataEntityVO.getKeepBehindList().size());

        BigDecimal balanceRatio= banlanceCount.divide(departmentCount, 2, RoundingMode.HALF_UP);
        BigDecimal keepBanlanceRatio= keepBanlanceCount.divide(departmentCount, 2, RoundingMode.HALF_UP);
        BigDecimal advanceRatio= advanceCount.divide(departmentCount, 2, RoundingMode.HALF_UP);
        BigDecimal keepAdvanceRatio= keepAdvancesCount.divide(departmentCount, 2, RoundingMode.HALF_UP);
        BigDecimal behindRatio= behindCount.divide(departmentCount, 2, RoundingMode.HALF_UP);
        BigDecimal keepBehindRatio= keepBehindCount.divide(departmentCount, 2, RoundingMode.HALF_UP);
        indicatorDataEntityVO.getPieChartDataVOS().add(new PieChartDataVO("持平",balanceRatio));
        indicatorDataEntityVO.getPieChartDataVOS().add(new PieChartDataVO("持续持平",keepBanlanceRatio));
        indicatorDataEntityVO.getPieChartDataVOS().add(new PieChartDataVO("持续进步",keepAdvanceRatio));
        indicatorDataEntityVO.getPieChartDataVOS().add(new PieChartDataVO("持续退步",keepBehindRatio));
        indicatorDataEntityVO.getPieChartDataVOS().add(new PieChartDataVO("进步",advanceRatio));
        indicatorDataEntityVO.getPieChartDataVOS().add(new PieChartDataVO("退步",behindRatio));



    }


    /**
     * 计算本期科室情况
     *
     * @param indicatorDataEntityDto
     * @param mulIndicatorDataDto
     * @param indicatorDataEntityVO
     */
    public void currentPeriodDepartmentData(IndicatorDataEntityDto indicatorDataEntityDto, MulIndicatorDataDto mulIndicatorDataDto, IndicatorDataEntityVO indicatorDataEntityVO) {
        //对所有涉及到的id进行去重
        String ids = mulIndicatorDataDto.getIds();
        List<String> elementIds = new ArrayList<>();
        String[] split = ids.split(",");
        for (String s : split) {
            elementIds.add(s);
        }
        elementIds = elementIds.stream().distinct().collect(Collectors.toList());
        // 求出指定时间区间的 天表数据之和
        indicatorDataEntityDto.setElementIds(elementIds);
        List<String> times = indicatorDataEntityDto.getTimes();
        int size = times.size();
        indicatorDataEntityDto.setStartTime(times.get(0));
        indicatorDataEntityDto.setEndTime(times.get(size - 1));
        //当前（本期）科室数据
        List<DepartmentIndicatorEntity> curDayData = indicatorAnalysisMapper.queryEscalationGroupByDept(indicatorDataEntityDto); //天表数据
        //计算去年及前年同期时间
        fillYoyime(indicatorDataEntityDto);

        // 去年同期科室数据
        List<String> lastYoyTimes = indicatorDataEntityDto.getLastYoyTimes();
        size = lastYoyTimes.size();
        indicatorDataEntityDto.setStartTime(lastYoyTimes.get(0));
        indicatorDataEntityDto.setEndTime(lastYoyTimes.get(size - 1));
        //去年同期科室数据
        List<DepartmentIndicatorEntity> lastDayData = indicatorAnalysisMapper.queryEscalationGroupByDept(indicatorDataEntityDto); //天表数据

        // 前年同期科室数据
        List<String> previousYoyTimes = indicatorDataEntityDto.getPreviousYoyTimes();
        size = previousYoyTimes.size();
        indicatorDataEntityDto.setStartTime(previousYoyTimes.get(0));
        indicatorDataEntityDto.setEndTime(previousYoyTimes.get(size - 1));
        //前年同期科室数据
        List<DepartmentIndicatorEntity> previousDayData = indicatorAnalysisMapper.queryEscalationGroupByDept(indicatorDataEntityDto); //天表数据

        //根据科室进行分组
        Map<String, List<DepartmentIndicatorEntity>> curMapValue = curDayData.stream().collect(Collectors.groupingBy(e -> e.getDeptName()));
        Map<String, List<DepartmentIndicatorEntity>> lastMapValue = lastDayData.stream().collect(Collectors.groupingBy(e -> e.getDeptName()));
        Map<String, List<DepartmentIndicatorEntity>> previousMapValue = previousDayData.stream().collect(Collectors.groupingBy(e -> e.getDeptName()));

        List<DepartmentVO> advanceList = new ArrayList<>();//进步科室
        List<DepartmentVO> behindList = new ArrayList<>();//退步科室
        List<DepartmentVO> banlanceList = new ArrayList<>();//持平科室

        List<DepartmentVO> keepAdvanceList = new ArrayList<>();//持续进步科室
        List<DepartmentVO> keepBehindList = new ArrayList<>();//持续退步科室
        List<DepartmentVO> keepBanlanceList = new ArrayList<>();//持续持平科室
        // 遍历部门
        List<DepartmentDto> departmentDtoList = indicatorDataEntityDto.getDepartmentDtoList();
        for (DepartmentDto departmentDto : departmentDtoList) {
            List<DepartmentIndicatorEntity> curList = curMapValue.get(departmentDto.getDepartmentName());
            List<DepartmentIndicatorEntity> lastList = lastMapValue.get(departmentDto.getDepartmentName());
            List<DepartmentIndicatorEntity> previousList = previousMapValue.get(departmentDto.getDepartmentName());

            String indexValue = "0";
            String lastYoyValue = "0";
            String previousYoyValue = "0";
            //解析当前指标的公式，通过元素值计算指标值
            String formula = mulIndicatorDataDto.getCalculationFormulaId();
            if (curList != null) {
                Map<String, String> mapValue = curList.stream().collect(Collectors.toMap(e -> "${" + e.getId() + "}", e -> e.getElementNumber()));
                indexValue = Calculator.conversionToSting(formula, mapValue);//当前指标值,如果当前指标涉及到多个元素计算，那么结果就是多元素数据计算的值，如果不涉及，就是其本身的值
                if (indexValue == "-") {
                    indexValue = "0";
                }
            }
            if (lastList != null) {
                Map<String, String> mapLastValue = lastList.stream().collect(Collectors.toMap(e -> "${" + e.getId() + "}", e -> e.getElementNumber()));
                lastYoyValue = Calculator.conversionToSting(formula, mapLastValue);//去年指标值,如果当前指标涉及到多个元素计算，那么结果就是多元素数据计算的值，如果不涉及，就是其本身的值
                if (lastYoyValue == "-") {
                    lastYoyValue = "0";
                }
            }
            if (previousList != null) {
                Map<String, String> mapPreviousValue = previousList.stream().collect(Collectors.toMap(e -> "${" + e.getId() + "}", e -> e.getElementNumber()));
                previousYoyValue = Calculator.conversionToSting(formula, mapPreviousValue);//前年指标值,如果当前指标涉及到多个元素计算，那么结果就是多元素数据计算的值，如果不涉及，就是其本身的值
                if (previousYoyValue == "-") {
                    previousYoyValue = "0";
                }
            }
            // 比较今年、去年、前年时期的值，得出进步、退步、持平的科室
            BigDecimal indexDecimal = new BigDecimal(indexValue);
            BigDecimal lastDecimal = new BigDecimal(lastYoyValue);
            BigDecimal previousDecimal = new BigDecimal(previousYoyValue);
            int curCompare = indexDecimal.compareTo(lastDecimal);
            int lastCompare = lastDecimal.compareTo(previousDecimal);
            DepartmentVO departmentVO = new DepartmentVO();
            departmentVO.setDepartmentName(departmentDto.getDepartmentName());
            //先分为三个大类  进步 退步 持平  然后在三个大类里面细分小类
            if (curCompare > 0) {
                //进步里面分为进步和持续进步
                if (lastCompare > 0) {
                    //持续进步
                    keepAdvanceList.add(departmentVO);
                } else {
                    //进步
                    advanceList.add(departmentVO);
                }

            } else if (curCompare == 0) {
                //持平里面分为持平和持续持平
                if (lastCompare == 0) {
                    //持续持平
                    keepBanlanceList.add(departmentVO);
                } else {
                    //持平
                    banlanceList.add(departmentVO);
                }

            } else {
                //退步里面分为退步和持续退步
                if (lastCompare <= 0) {
                    //持续退步
                    keepBehindList.add(departmentVO);
                } else {
                    //退步
                    behindList.add(departmentVO);
                }
            }

        }
        indicatorDataEntityVO.setAdvanceList(advanceList);
        indicatorDataEntityVO.setKeepAdvanceList(keepAdvanceList);

        indicatorDataEntityVO.setBehindList(behindList);
        indicatorDataEntityVO.setKeepBehindList(keepBehindList);

        indicatorDataEntityVO.setBanlanceList(banlanceList);
        indicatorDataEntityVO.setKeepBanlanceList(keepBanlanceList);


    }

    /**
     * 计算去年及前年同比日期
     *
     * @param
     */
    public void fillYoyime(IndicatorDataEntityDto indicatorDataEntityDto) {
        //获取参数中需要查询的时间
        List<String> times = indicatorDataEntityDto.getTimes();
        if (CollectionUtils.isEmpty(times)) {
            throw new RuntimeException("查询时间为空");
        }
        List<String> lastYoyTimes = getYoyTime(times);//获取去年同比时间集合
        List<String> previousYoyTimes = getYoyTime(lastYoyTimes);//获取前年同比时间集合

        indicatorDataEntityDto.setLastYoyTimes(lastYoyTimes);
        indicatorDataEntityDto.setPreviousYoyTimes(previousYoyTimes);
    }


    /**
     * 计算同比时间
     *
     * @param
     * @param
     * @return
     */
    public List<String> getYoyTime(List<String> times) {
        List<String> lastYearDates = new ArrayList<>();
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
        boolean isWholeMonth;
        // 使用流式操作按年份和月份分组,分组后的map中 键是年和月，如2024-01， 值是List集合，存的是相同年月的字符串,同时指定插入顺序，采用LinkedHashMap
        Map<String, List<String>> groupedDates = times.stream().collect(Collectors.groupingBy(date -> date.substring(0, 7), LinkedHashMap::new, Collectors.toList()));
        for (Map.Entry<String, List<String>> entry : groupedDates.entrySet()) {
            List<String> groupTimes = entry.getValue();
            // 判断是否是一整个月
            isWholeMonth = isWholeMonth(groupTimes);
            for (String currentDate : groupTimes) {
                LocalDate date = LocalDate.parse(currentDate, formatter);
                if (isWholeMonth) {
                    int lastYearMonthLength = date.minusYears(1).lengthOfMonth(); // 获取去年同月的天数
                    LocalDate lastYearStartDate = LocalDate.of(date.getYear() - 1, date.getMonth(), 1); // 去年同月的第一天
                    for (int i = 0; i < lastYearMonthLength; i++) {
                        lastYearDates.add(lastYearStartDate.plusDays(i).format(formatter));
                    }
                    break;
                } else {
                    LocalDate lastYearDate = date.minusYears(1);
                    lastYearDates.add(lastYearDate.format(formatter));
                }
            }
        }


        return lastYearDates;
    }

    /**
     * 判断当前时间数组是否为一整个月
     */
    private static boolean isWholeMonth(List<String> times) {
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
        LocalDate firstDate = LocalDate.parse(times.get(0), formatter);
        LocalDate lastDate = LocalDate.parse(times.get(times.size() - 1), formatter);
        if (firstDate.getDayOfMonth() != 1) {
            return false;
        }
        int daysInMonth = firstDate.lengthOfMonth();
        return lastDate.getDayOfMonth() == daysInMonth;
    }

    /**
     * 计算本期指标情况
     *
     * @param indicatorDataEntityDto
     * @param mulIndicatorDataDto
     * @param indicatorDataEntityVO
     */
    public void currentPeriodIndicatorData(IndicatorDataEntityDto indicatorDataEntityDto, MulIndicatorDataDto mulIndicatorDataDto, IndicatorDataEntityVO indicatorDataEntityVO) {
        //对所有涉及到的id进行去重
        String ids = mulIndicatorDataDto.getIds();
        List<String> elementIds = new ArrayList<>();
        CurrentPeriodIndicatorValueVO curPeriodValue = new CurrentPeriodIndicatorValueVO();
        if (!org.springframework.util.StringUtils.isEmpty(ids)) {
            String[] split = ids.split(",");
            for (String s : split) {
                elementIds.add(s);
            }
            elementIds = elementIds.stream().distinct().collect(Collectors.toList());
            //查询元素定义表，确定元素数据来源 天表、月表、手填表等
            List<ElementDataEntity> elementDataEntities = elementDataMapper.query(elementIds);
            //分别得出天表，月表，手填表的元素数据
            List<ElementDataEntity> dayTable = elementDataEntities.stream().filter(s -> StringUtils.isNotBlank(s.getDataTable()) && "1".equals(s.getDataTable())).collect(Collectors.toList());
            List<ElementDataEntity> monthTable = elementDataEntities.stream().filter(s -> StringUtils.isNotBlank(s.getDataTable()) && "2".equals(s.getDataTable())).collect(Collectors.toList());
            List<ElementDataEntity> handTable = elementDataEntities.stream().filter(s -> StringUtils.isNotBlank(s.getDataTable()) && "3".equals(s.getDataTable())).collect(Collectors.toList());


            List<String> times = indicatorDataEntityDto.getTimes();
            // 存放当前时间的所有的天表、月表、手填表数据
            List<DepartmentIndicatorEntity> departmentIndicatorEntityList = new ArrayList<>();
            //查出天表数据 求的是指定时间区间的 天表数据之和
            if (!org.springframework.util.CollectionUtils.isEmpty(dayTable)) {
                indicatorDataEntityDto.setElementIds(dayTable.stream().map(ElementDataEntity::getId).collect(Collectors.toList()));
                int size = times.size();
                indicatorDataEntityDto.setStartTime(times.get(0));
                indicatorDataEntityDto.setEndTime(times.get(size - 1));
                List<DepartmentIndicatorEntity> dayData = indicatorAnalysisMapper.queryEscalationGroupByDay(indicatorDataEntityDto); //天表数据
                departmentIndicatorEntityList.addAll(dayData);
            }

            List<String> groupTimes;
            //查出月表数据 求的是指定时间区间的 月表数据之和（月表每个月数据就一条 求和与不求和没有区别）
            if (!org.springframework.util.CollectionUtils.isEmpty(monthTable)) {
                indicatorDataEntityDto.setElementIds(monthTable.stream().map(ElementDataEntity::getId).collect(Collectors.toList()));
                //月数据只需要时间精确到月
                groupTimes = times.stream().map(time -> time.substring(0, 7)).distinct().collect(Collectors.toList());
                indicatorDataEntityDto.setGroupTimes(groupTimes);
                List<DepartmentIndicatorEntity> monthData = indicatorAnalysisMapper.queryEscalationNew(indicatorDataEntityDto); //月表数据
                departmentIndicatorEntityList.addAll(monthData);
            }

            if (!org.springframework.util.CollectionUtils.isEmpty(handTable)) {
                indicatorDataEntityDto.setElementIds(handTable.stream().map(ElementDataEntity::getId).collect(Collectors.toList()));

                //手填表数据只需要时间精确到月
                groupTimes = times.stream().map(time -> time.substring(0, 7)).distinct().collect(Collectors.toList());
                indicatorDataEntityDto.setGroupTimes(groupTimes);
                // 查找taskId  精确到每个部门的每个月的每一条
                List<String> taskIds = indicatorAnalysisMapper.selectReportTasks(groupTimes, indicatorDataEntityDto.getUserInfo().getWardName(), indicatorDataEntityDto.getUserInfo().getParentDepartmentId());
                List<DepartmentIndicatorEntity> handTableData = new ArrayList<>();
                if (taskIds.size() > 0) {
                    indicatorDataEntityDto.setTaskIds(taskIds);
                    handTableData = indicatorAnalysisMapper.queryIndexValueNew(indicatorDataEntityDto); //手填表数据
                }
                departmentIndicatorEntityList.addAll(handTableData);
            }

            Map<String, String> mapValue = new HashMap<>();
            //把departmentIndicatorEntityList中id相同的进行累加，返回的还是一个list集合，然后放入到一个map中，计算当前time的指标值
            if (!org.springframework.util.StringUtils.isEmpty(departmentIndicatorEntityList)) {
                mapValue = departmentIndicatorEntityList.stream().collect(Collectors.groupingBy(e -> String.format("${%s}", e.getId()), Collectors.collectingAndThen(Collectors.summingDouble(e -> Double.parseDouble(e.getElementNumber())), sum -> String.valueOf(sum))));
            }
            //解析当前指标的公式，通过元素值计算指标值
            String formula = mulIndicatorDataDto.getCalculationFormulaId();
            String indexValue = Calculator.conversionToSting(formula, mapValue);//当前指标值,如果当前指标涉及到多个元素计算，那么结果就是多元素数据计算的值，如果不涉及，就是其本身的值

            String moleculeValue = "-";
            String denominatorValue = "-";
            if (!org.springframework.util.StringUtils.isEmpty(formula)) {
                String[] splitFormula = formula.split("/");
                if (splitFormula.length > 1) {
                    //大于1说明有分子分母
                    String moleculeFormula = splitFormula[0];//分子的公式
                    moleculeValue = Calculator.conversionToSting(moleculeFormula, mapValue);//分子值

                    String denominatorFormula = splitFormula[1];//分母的公式
                    denominatorValue = Calculator.conversionToSting(denominatorFormula, mapValue);//分母值
                }
            }


            curPeriodValue.setIndexName(mulIndicatorDataDto.getIndexName());//指标名
            curPeriodValue.setIndexValue(indexValue);//指标值
            curPeriodValue.setMoleculeName(mulIndicatorDataDto.getMoleculeName() == null ? "-" : mulIndicatorDataDto.getMoleculeName());//分子名
            curPeriodValue.setMoleculeValue(moleculeValue);//分子值
            curPeriodValue.setDenominatorName(mulIndicatorDataDto.getDenominatorName() == null ? "-" : mulIndicatorDataDto.getDenominatorName());//分母名
            curPeriodValue.setDenominatorValue(denominatorValue);//分母值


            indicatorDataEntityVO.setCurrentPeriodIndicatorValueVO(curPeriodValue);


        } else {
            curPeriodValue.setIndexName(mulIndicatorDataDto.getIndexName());//指标名
            curPeriodValue.setIndexValue("-");//指标值
            curPeriodValue.setMoleculeName(mulIndicatorDataDto.getMoleculeName() == null ? "-" : mulIndicatorDataDto.getMoleculeName());//分子名
            curPeriodValue.setMoleculeValue("-");//分子值
            curPeriodValue.setDenominatorName(mulIndicatorDataDto.getDenominatorName() == null ? "-" : mulIndicatorDataDto.getDenominatorName());//分母名
            curPeriodValue.setDenominatorValue("-");//分母值
            indicatorDataEntityVO.setCurrentPeriodIndicatorValueVO(curPeriodValue);
        }
    }


}